package com.zbkj.common.utils;

import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;


@Slf4j
public class DateUtil {
    public static String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";

    public static String HHmmss = "HHmmss";

    public static String yyyy_MM_dd = "yyyy-MM-dd";

    public static String yyyyMMdd = "yyyyMMdd";

    public static String yyyyMM = "yyyyMM";

    public static String yyyyMMddHHmmss = "yyyyMMddHHmmss";

    public static String yyyy_MM_dd_T_HH_mm_ss_Z = "yyyy-MM-dd'T'HH:mm:ss'Z'";

    public static long DAY_MILLISECOND = 24 * 60 * 60 * 1000;


    /**
     * 使用ThreadLocal来解决SimpleDateFormat非线程安全的问题
     */
    private static ThreadLocal<Map<String, SimpleDateFormat>> threadLocal = new ThreadLocal<Map<String, SimpleDateFormat>>() {
        @Override
        protected Map<String, SimpleDateFormat> initialValue() {
            log.debug("Thread-Id:{} init pattern:{}", Thread.currentThread().getId(), Thread.currentThread());
            return new HashMap<String, SimpleDateFormat>(2);
        }
    };

    public static SimpleDateFormat getSimpleDateFormat(final String format) {
        Map<String, SimpleDateFormat> dateFormatMap = threadLocal.get();
        SimpleDateFormat sdf = dateFormatMap.get(format);
        if (sdf == null) {
            log.debug("Thread-Id:{} put new SimpleDateFormat to map ,the format:{}", Thread.currentThread().getId(), format);
            sdf = new SimpleDateFormat(format);
            dateFormatMap.put(format, sdf);
        }
        return sdf;
    }

    public static String getYesterdayDateStr() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, -1);

        return getSimpleDateFormat(yyyy_MM_dd).format(calendar.getTime());
    }

    /**
     * 昨天时间
     *
     * @param format DateUtil.yyyy_MM_dd_HH_mm_ss/DateUtil.yyyy_MM_dd
     * @return
     */
    public static String getYesterday(String format) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, -1);

        return getSimpleDateFormat(format).format(calendar.getTime());
    }


    /**
     * 当前 间隔时间
     *
     * @param format DateUtil.yyyy_MM_dd_HH_mm_ss/DateUtil.yyyy_MM_dd
     * @param hours  正数 当前hours小时之后 负数 hours小时之前  例如：5/-5 当前时间5小时之后/当前时间 5小时之前
     * @return
     */
    public static String getDate(String format, Integer hours) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.HOUR, hours);
        return getSimpleDateFormat(format).format(calendar.getTime());
    }

    /**
     * 格式化日期为 yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return
     */
    public static String formatDate(Date date) {
        return getSimpleDateFormat(yyyy_MM_dd_HH_mm_ss).format(date);
    }

    /**
     * 格式化日期为 yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return
     */
    public static String formatDateYMDHMS(Date date) {
        return getSimpleDateFormat(yyyyMMddHHmmss).format(date);
    }

    /**
     * 格式化日期为 yyyy-MM-dd
     *
     * @param date
     * @return
     */
    public static String formatDateYMD(Date date) {
        return getSimpleDateFormat(yyyy_MM_dd).format(date);
    }

    /**
     * 格式化日期为 yyyyMMdd
     *
     * @param date
     * @return
     */
    public static String formatDateYYYYMMdd(Date date) {
        return getSimpleDateFormat(yyyyMMdd).format(date);
    }

    /**
     * 格式化日期为 HHmmss
     *
     * @param date
     * @return
     */
    public static String formatDateHHmmss(Date date) {
        return getSimpleDateFormat(HHmmss).format(date);
    }


    public static String formatDateYM(Date date) {
        return getSimpleDateFormat(yyyyMM).format(date);
    }

    /**
     * 格式化日期为 yyyyMMdd
     *
     * @param date
     * @return
     */
    public static String formatDateyyyy_MM_dd_T_HH_mm_ss_Z(Date date) {
        return getSimpleDateFormat(yyyyMMdd).format(date);
    }

    /**
     * 字符 转时间戳
     *
     * @param str
     * @return
     * @throws Exception
     */
    public static Long dateToStamp(String str) {
        SimpleDateFormat simpleDateFormat = getSimpleDateFormat(yyyy_MM_dd);
        Date date = null;
        try {
            date = simpleDateFormat.parse(str);
            long ts = date.getTime();
            return ts;
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 获取n 年后今天的时间
     *
     * @param n 年数
     * @return
     */
    public static Date getNextYear(Integer n) {
        // 取时间
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        // 把日期往后增加一年.整数往后推,负数往前移动
        calendar.add(Calendar.YEAR, n);
        date = calendar.getTime();
        return date;

    }

    private static final DateTimeFormatter DATETIME14 = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    public static LocalDateTime str10ToLdt(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        return LocalDateTime.parse(str, DATETIME14);
    }

    public static LocalDateTime str09ToLdt(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        return LocalDateTime.parse(str, DATETIME19);
    }

    public static LocalDate str11ToLdt(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        return LocalDate.parse(str, DATETIME11);
    }

    public static LocalTime str12ToLdt(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        return LocalTime.parse(str, DATETIME12);
    }

    private static final String DEFAULT_STR = "";
    private static final DateTimeFormatter DATETIME19 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter DATETIME20 = DateTimeFormatter.ofPattern(yyyy_MM_dd_T_HH_mm_ss_Z);
    private static final DateTimeFormatter DATETIME11 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter DATETIME12 = DateTimeFormatter.ofPattern("HH:mm:ss");

    /**
     * 时间LocalDateTime转换成yyyy-MM-dd HH:mm:ss格式字符串
     *
     * @param ldt
     * @return
     */
    public static String ldt2Str19(LocalDateTime ldt) {
        if (ldt == null) {
            return DEFAULT_STR;
        }
        return DATETIME19.format(ldt);
    }

    public static String utcToLocal(String str) {
        if (StringUtils.isBlank(str)) {
            return "";
        }
        SimpleDateFormat simpleDateFormat = getSimpleDateFormat(yyyy_MM_dd_T_HH_mm_ss_Z);
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        try {
            Date date = simpleDateFormat.parse(str);
            String s = formatDate(date);
            return s;
        } catch (ParseException e) {
            e.printStackTrace();
            return "";
        }
    }


    /**
     * Description: 本地时间转化为UTC时间
     *
     * @param localTime
     * @return UTC标准时间
     */
    public static String localToUTC(String localTime) {
        /*创建格式化时间对象simpleDateFormat，并初始化格式yyyy-MM-dd HH:mm:ss*/
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date localDate = null;
        try {
            localDate = sdf.parse(localTime);
        } catch (ParseException e) {
            e.printStackTrace();
            return "";
        }
        long localTimeInMillis = localDate.getTime();
        /** long时间转换成Calendar */
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(localTimeInMillis);
        /** 取得时间偏移量 */
        int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
        /** 取得夏令时差 */
        int dstOffset = calendar.get(Calendar.DST_OFFSET);
        /** 从本地时间里扣除这些差量，即可以取得UTC时间*/
        calendar.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        /** 取得的时间就是UTC标准时间 */
        Date utcDate = new Date(calendar.getTimeInMillis());
        return sdf.format(utcDate);
    }

    /**
     * Description: 本地时间转化为UTC时间
     *
     * @param localTime
     * @return UTC标准时间
     */
    public static String localToUTC(LocalDateTime localTime) {
        /*创建格式化时间对象simpleDateFormat，并初始化格式yyyy-MM-dd HH:mm:ss*/

        Date localDate = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            localDate = sdf.parse(ldt2Str19(localTime));
        } catch (ParseException e) {
            e.printStackTrace();
            return "";
        }
        long localTimeInMillis = localDate.getTime();
        /** long时间转换成Calendar */
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(localTimeInMillis);
        /** 取得时间偏移量 */
        int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
        /** 取得夏令时差 */
        int dstOffset = calendar.get(Calendar.DST_OFFSET);
        /** 从本地时间里扣除这些差量，即可以取得UTC时间*/
        calendar.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        /** 取得的时间就是UTC标准时间 */
        Date utcDate = new Date(calendar.getTimeInMillis());
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        return sdf2.format(utcDate);
    }

    public static LocalDate convertDateToLocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
    }

    /**
     * 获取两个日期之间的所有日期 (年月日)
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static List<String> getBetweenDate(String startTime, String endTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 声明保存日期集合
        List<String> list = new ArrayList<String>();
        try {
            // 转化成日期类型
            Date startDate = sdf.parse(startTime);
            Date endDate = sdf.parse(endTime);

            //用Calendar 进行日期比较判断
            Calendar calendar = Calendar.getInstance();
            while (startDate.getTime() <= endDate.getTime()) {
                // 把日期添加到集合
                list.add(sdf.format(startDate));
                // 设置日期
                calendar.setTime(startDate);
                //把日期增加一天
                calendar.add(Calendar.DATE, 1);
                // 获取增加后的日期
                startDate = calendar.getTime();
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return list;
    }


    /**
     * 获取两个日期之间的所有日期 (年月日)
     *
     * @param startLocalDate
     * @param endLocalDate
     * @return
     */
    public static List<LocalDate> getBetweenDate(LocalDate startLocalDate, LocalDate endLocalDate) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 声明保存日期集合
        List<LocalDate> list = new ArrayList<LocalDate>();
        try {
            // 转化成日期类型
            Instant startInstant = startLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
            Date startDate = Date.from(startInstant);
            Instant endInstant = endLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
            Date endDate = Date.from(endInstant);

            //用Calendar 进行日期比较判断
            Calendar calendar = Calendar.getInstance();
            while (startDate.getTime() <= endDate.getTime()) {
                // 把日期添加到集合
                list.add(convertDateToLocalDate(startDate));
                // 设置日期
                calendar.setTime(startDate);
                //把日期增加一天
                calendar.add(Calendar.DATE, 1);
                // 获取增加后的日期
                startDate = calendar.getTime();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }


    public static void main(String[] args) {
        LocalTime startDate = str12ToLdt("23:34:12");
        LocalTime endDate = str12ToLdt("23:34:12");
        LocalTime startDate2 = str12ToLdt("23:34:12");
        LocalTime endDate2 = str12ToLdt("23:34:15");
        System.out.println(startDate);
        System.out.println(endDate);
        System.out.println(endDate.equals(startDate));
        System.out.println(endDate2.isAfter(startDate2));

        String startStr = "2022-02-26";
        String endStr = "2022-03-09";
        LocalDate startLocalDate = LocalDate.parse(startStr);
        LocalDate endLocalDate = LocalDate.parse(endStr);
        List<String> list = getBetweenDate(startStr, endStr);
        System.out.println(list);
        List<LocalDate> list2 = getBetweenDate(startLocalDate, endLocalDate);
        System.out.println(list2);
    }
}
